Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Threading
Imports System.Xml
Imports System.IO
Imports System.Xml.Serialization
Imports System.Diagnostics
Imports C4F.DevKit.Telephony.Properties
Imports System.ComponentModel

Namespace C4F.DevKit.Telephony

	''' <summary>
	''' This class provides basic telephony functionality.
	''' </summary>
	Public Class TapiManager
		Inherits Component
		#Region "Members"

		Private tapiBase As TapiBase = New TapiBase()

		#End Region

		#Region "Public Properties"

		''' <summary>
		''' Represents the currently connected call.
		''' </summary>
		Public ReadOnly Property CurrentCall() As CallInfo

			Get
				Return tapiBase.CurrentCall
			End Get

		End Property

		''' <summary>
		''' Represents the currently available calls.
		''' </summary>
		Public ReadOnly Property AvailableCalls() As List(Of CallInfo)

			Get
				Return tapiBase.AvailableCalls
			End Get

		End Property

		''' <summary>
		''' Represents the name of the "default line".
		''' </summary>
		Public ReadOnly Property DefaultLineName() As String
			Get
				Return tapiBase.DefaultLineName
			End Get
		End Property

		#End Region

		#Region "Delegates and Events"

		''' <summary>
		''' Delegate to handle the incoming and outgoing call event.
		''' </summary>
		''' <param name="callInfo">Information about the call which initiated the event.</param>
		Public Delegate Sub CallNotificationEventHandler(ByVal callInfo As CallInfo)

		''' <summary>
		''' This event is raised when there is an incoming call.
		''' </summary>
		Public Event OnIncomingCall As CallNotificationEventHandler

		''' <summary>
		''' This event is raised when there is an outging call.
		''' </summary>
		Public Event OnOutgoingCall As CallNotificationEventHandler

		''' <summary>
		''' This event is raised when a call has been connected.
		''' </summary>
		Public Event OnCallConnected As CallNotificationEventHandler

		''' <summary>
		''' This event is raised when a call has been disconnected.
		''' </summary>
		Public Event OnCallDisconnected As CallNotificationEventHandler

		''' <summary>
		''' This event is raised when a call is placed on hold.
		''' </summary>
		Public Event OnCallHold As CallNotificationEventHandler

		''' <summary>
		''' Delegate to handle the digit event.
		''' </summary>
		''' <param name="callInfo">Information about the call which initiated the digit event.</param>
		''' <param name="digit">Received digit.</param>
		Public Delegate Sub DigitNotificationEventHandler(ByVal callInfo As CallInfo, ByVal digit As Char)

		''' <summary>
		''' This event is raised when a digit is received.
		''' </summary>
		Public Event OnDigitReceived As DigitNotificationEventHandler

		''' <summary>
		''' Delegate to handle the end of playback file event.
		''' </summary>
		''' <param name="callInfo">Information about the call on which the file was being played.</param>
		Public Delegate Sub EndOfPlaybackNotificationEventHandler(ByVal callInfo As CallInfo)

		''' <summary>
		''' This event is raised when the end of playback file event is generated.
		''' </summary>
		Public Event OnEndOfFilePlayback As EndOfPlaybackNotificationEventHandler

		#End Region

		#Region "Public Methods"

		''' <summary>
		''' Gets the communication lines that are currently available.
		''' </summary>
		''' <returns>List of available lines with audio support.</returns>
		''' <exception cref="TapiManagerException">If there is an error while getting the available address lines.</exception>
		Public Function GetAvailableLines() As List(Of Line)
			Return tapiBase.GetAvailableLines()
		End Function

		''' <summary>
		''' Gets the communication lines that are currently available.
		''' </summary>
		''' <param name="withDefault">Whether or not to include "default" line</param>
		''' <returns>List of available lines with audio support.</returns>
		''' <exception cref="TapiManagerException">If there is an error while getting the available address lines.</exception>
		Public Function GetAvailableLines(ByVal withDefault As Boolean) As List(Of Line)
			Return tapiBase.GetAvailableLines(withDefault)
		End Function

		''' <summary>
		''' Makes a call to the specified phone number.
		''' </summary>
		''' <param name="targetAddress">Phone number to be dialed.</param>
		''' <exception cref="ArgumentNullException">The 'targetAddress' is null.</exception>
		''' <exception cref="InvalidOperationException">Another call is already connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while making the call.</exception>
		Public Sub MakeCall(ByVal targetAddress As String)
			tapiBase.MakeCall(targetAddress)
		End Sub

		''' <summary>
		''' Makes a call to the specified phone number using the specified address line.
		''' </summary>
		''' <param name="targetAddress">Phone number to be dialed.</param>
		''' <param name="lineName">Name of the line to be used to make the call.</param>
		''' <exception cref="ArgumentNullException">The 'targetAddress' is null (OR) the 'lineName' is null.</exception>
		''' <exception cref="InvalidOperationException">Another call is already connected.</exception>
		''' <exception cref="TapiManagerException">Invalid 'lineName' (OR) the specified line does not support audio (OR) 
		''' there is an error while dialing the phone number.</exception>
		Public Sub MakeCall(ByVal targetAddress As String, ByVal lineName As String)
			tapiBase.MakeCall(targetAddress, lineName)
		End Sub

		''' <summary>
		''' Disconnects the current connected call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while disconnecting the call.</exception>
		Public Sub DisconnectCall()
			tapiBase.DisconnectCall()
		End Sub

		''' <summary>
		''' Answers the latest incoming call.
		''' </summary>
		''' <exception cref="InvalidOperationException">Another call is already connected (OR) there is no incoming call.</exception>
		''' <exception cref="TapiManagerException">If there is an error while answering the call.</exception>
		Public Sub AnswerCall()
			tapiBase.AnswerCall()
		End Sub

		''' <summary>
		''' Answers an incoming call.
		''' </summary>
		''' <param name="call">Call to be answered.</param>
		''' <exception cref="ArgumentNullException">The 'call' is null.</exception>
		''' <exception cref="InvalidOperationException">Another call is already connected.</exception>
		''' <exception cref="ArgumentException">The 'call' is not valid.</exception>
		''' <exception cref="TapiManagerException">If there is an error while answering the call.</exception>
		Public Sub AnswerCall(ByVal [call] As CallInfo)
			tapiBase.AnswerCall([call])
		End Sub

		''' <summary>
		''' Puts the current call on hold.
		''' </summary>
		''' <returns>True if the method succeeds.</returns>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the call is already on hold.</exception>
		Public Function Hold() As Boolean
			Return tapiBase.Hold()
		End Function

		''' <summary>
		''' Resumes the current call which is on hold.
		''' </summary>
		''' <returns>True if the method succeeds.</returns>
		''' <exception cref="InvalidOperationException">Current call is not on hold.</exception>
		Public Function [Resume]() As Boolean
			Return tapiBase.Resume()
		End Function

		''' <summary>
		''' Initializes an  object of TapiManager.
		''' </summary>
		''' <exception cref="TapiManagerException">If there is an error while registering the lines for Tapi events.</exception>
		Public Sub New()
			AddHandler tapiBase.OnIncomingCall, AddressOf tapiBase_OnIncomingCall
			AddHandler tapiBase.OnCallConnected, AddressOf tapiBase_OnCallConnected
			AddHandler tapiBase.OnCallDisconnected, AddressOf tapiBase_OnCallDisconnected
			AddHandler tapiBase.OnOutgoingCall, AddressOf tapiBase_OnOutgoingCall
			AddHandler tapiBase.OnCallHold, AddressOf tapiBase_OnCallHold
			AddHandler tapiBase.OnDigitReceived, AddressOf tapiBase_OnDigitReceived
			AddHandler tapiBase.OnEndOfFilePlayback, AddressOf tapiBase_OnEndOfFilePlayback
		End Sub

		''' <summary>
		''' Starts the digit detection on currently connected call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the DTMF is not supported on current line.</exception>
		''' <exception cref="TapiManagerException">If there is an error while registering for digit detection.</exception>
		Public Sub StartDigitDetection()
			tapiBase.StartDigitDetection()
		End Sub

		''' <summary>
		''' Stops the digit detection on currently connected call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the DTMF is not supported on current line.</exception>
		''' <exception cref="TapiManagerException">If there is an error while unregistering for digit detection.</exception>
		Public Sub StopDigitDetection()
			tapiBase.StopDigitDetection()
		End Sub

		''' <summary>
		''' This method causes digits to be output on the current call. Valid digits are 0 through 9, '*', '#', 'A', 'B', 'C', and 'D'.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the DTMF is not supported on current line.</exception>
		''' <exception cref="TapiManagerException">If there is an error while generating the digits.</exception>
		Public Sub GenerateDigits(ByVal digits As String)
			tapiBase.GenerateDigits(digits)
		End Sub

		''' <summary>
		''' Opens a file dialog and plays selected audio files on the current call.
		''' </summary>
		''' <exception cref="ArgumentException">One of the specified file is not found (OR) one of the specified file is not in 'WAV' format.</exception>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while playing the file.</exception>
		Public Sub PlayFiles()
			Dim openFileDialog As System.Windows.Forms.OpenFileDialog = New System.Windows.Forms.OpenFileDialog()
			openFileDialog.Filter = "wav files (*.wav)|*.wav"
			openFileDialog.RestoreDirectory = True
			openFileDialog.Multiselect = True

			If openFileDialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
				Dim fileNamesArray As String() = openFileDialog.FileNames
				Dim fileNamesList As List(Of String) = New List(Of String)()

				For Each filename As String In fileNamesArray
					fileNamesList.Add(filename)
				Next filename

				tapiBase.PlayFiles(fileNamesList)
			End If
		End Sub

		''' <summary>
		''' Plays Specified audio files on the current call.
		''' </summary>
		''' <param name="filePaths">List of file paths to play.</param>
		''' <exception cref="ArgumentException">One of the specified file is not found (OR) one of the specified file is not in 'WAV' format.</exception>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while playing the file.</exception>
		Public Sub PlayFiles(ByVal filePaths As List(Of String))
			tapiBase.PlayFiles(filePaths)
		End Sub

		''' <summary>
		''' Opens a file dialog and plays selected audio file on the current call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while playing the file.</exception>
		Public Sub PlayFile()
			Dim openFileDialog As System.Windows.Forms.OpenFileDialog = New System.Windows.Forms.OpenFileDialog()
			openFileDialog.Filter = "wav files (*.wav)|*.wav"
			openFileDialog.RestoreDirectory = True

			If openFileDialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
				tapiBase.PlayFile(openFileDialog.FileName)
			End If
		End Sub

		''' <summary>
		''' Plays Specified audio file on the current call.
		''' </summary>
		''' <param name="filePath">Path of the audio file to play.</param>
		''' <exception cref="ArgumentNullException">The 'filePath' is null.</exception>
		''' <exception cref="ArgumentException">The 'filePath' is not specified (OR) the specified file is not found (OR) the specified file is not in 'WAV' format.</exception>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="TapiManagerException">If there is an error while playing the file.</exception>
		Public Sub PlayFile(ByVal filePath As String)
			tapiBase.PlayFile(filePath)
		End Sub

		''' <summary>
		''' Records the current call and saves with the file name selected in a new save file dialog
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="ArgumentException">The 'saveFilePath' is not specified (OR) there is an error while creating the target file.</exception>
		''' <exception cref="TapiManagerException">If there is an error while recording the call.</exception>
		Public Sub RecordCall()
			Dim saveFileDialog As System.Windows.Forms.SaveFileDialog = New System.Windows.Forms.SaveFileDialog()
			saveFileDialog.RestoreDirectory = True

			If saveFileDialog.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
				tapiBase.RecordCall(saveFileDialog.FileName)
			End If
		End Sub

		''' <summary>
		''' Records the current call and saves with the specified file name. 
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected.</exception>
		''' <exception cref="ArgumentNullException">The 'saveFilePath' is null.</exception>
		''' <exception cref="ArgumentException">The 'saveFilePath' is not specified (OR) there is an error while creating the target file.</exception>
		''' <exception cref="TapiManagerException">If there is an error while recording the call.</exception>
		Public Sub RecordCall(ByVal saveFilePath As String)
			tapiBase.RecordCall(saveFilePath)
		End Sub

		''' <summary>
		''' Stops the recording of the current call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the call recording is not in progress.</exception>
		''' <exception cref="TapiManagerException">If there is an error while stopping the call recording.</exception>
		Public Sub StopCallRecording()
			tapiBase.StopCallRecording()
		End Sub

		''' <summary>
		''' Stops the file playingon the current call.
		''' </summary>
		''' <exception cref="InvalidOperationException">No call is currently connected (OR) the playback is not in progress.</exception>
		''' <exception cref="TapiManagerException">If there is an error while stopping the file playing.</exception>
		Public Sub StopPlayingFile()
			tapiBase.StopPlayingFile()
		End Sub

		''' <summary>
		''' Unregisters all the registered lines and then ends the TAPI session.
		''' </summary>
		''' <exception cref="TapiManagerException">If there is an error while unregistering the tapi events.</exception>
		Public Sub TapiShutdown()
			tapiBase.TapiShutdown()
		End Sub

		#End Region

		#Region "Private Methods"

		''' <summary>
		''' This method handles incoming call event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnIncomingCall(ByVal [call] As CallInfo)
			RaiseEvent OnIncomingCall([call])
		End Sub

		''' <summary>
		''' This method handles incoming call event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnCallConnected(ByVal [call] As CallInfo)
			RaiseEvent OnCallConnected([call])
		End Sub

		''' <summary>
		''' This method handles incoming call event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnCallDisconnected(ByVal [call] As CallInfo)
			RaiseEvent OnCallDisconnected([call])
			Dim backgroundThread As Thread = New Thread(AddressOf ReinitializeTapi)
			backgroundThread.Start()
		End Sub

		''' <summary>
		''' This method handles incoming call event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnOutgoingCall(ByVal [call] As CallInfo)
			RaiseEvent OnOutgoingCall([call])
		End Sub

		''' <summary>
		''' This method handles incoming call event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnCallHold(ByVal [call] As CallInfo)
			RaiseEvent OnCallHold([call])
		End Sub

		''' <summary>
		''' This method handles incoming digits.
		''' </summary>
		''' <param name="call">Call object.</param>
		''' <param name="digit">Received digit.</param>
		Private Sub tapiBase_OnDigitReceived(ByVal [call] As CallInfo, ByVal digit As Char)
			RaiseEvent OnDigitReceived([call], digit)
		End Sub

		''' <summary>
		''' This method handles the end of playback file event.
		''' </summary>
		''' <param name="call">Call object.</param>
		Private Sub tapiBase_OnEndOfFilePlayback(ByVal [call] As CallInfo)
			RaiseEvent OnEndOfFilePlayback([call])
		End Sub

		''' <summary>
		''' Re-initializes the tapi session.
		''' </summary>
		Private Sub ReinitializeTapi()
			RemoveHandler tapiBase.OnIncomingCall, AddressOf tapiBase_OnIncomingCall
			RemoveHandler tapiBase.OnCallConnected, AddressOf tapiBase_OnCallConnected
			RemoveHandler tapiBase.OnCallDisconnected, AddressOf tapiBase_OnCallDisconnected
			RemoveHandler tapiBase.OnOutgoingCall, AddressOf tapiBase_OnOutgoingCall
			RemoveHandler tapiBase.OnCallHold, AddressOf tapiBase_OnCallHold
			RemoveHandler tapiBase.OnDigitReceived, AddressOf tapiBase_OnDigitReceived
			RemoveHandler tapiBase.OnEndOfFilePlayback, AddressOf tapiBase_OnEndOfFilePlayback

			tapiBase.TapiShutdown()
			tapiBase = New TapiBase()
			AddHandler tapiBase.OnIncomingCall, AddressOf tapiBase_OnIncomingCall
			AddHandler tapiBase.OnCallConnected, AddressOf tapiBase_OnCallConnected
			AddHandler tapiBase.OnCallDisconnected, AddressOf tapiBase_OnCallDisconnected
			AddHandler tapiBase.OnOutgoingCall, AddressOf tapiBase_OnOutgoingCall
			AddHandler tapiBase.OnCallHold, AddressOf tapiBase_OnCallHold
			AddHandler tapiBase.OnDigitReceived, AddressOf tapiBase_OnDigitReceived
			AddHandler tapiBase.OnEndOfFilePlayback, AddressOf tapiBase_OnEndOfFilePlayback
		End Sub

		#End Region

	End Class

End Namespace